home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume89 / workbnch / mymenu.1 < prev   
Internet Message Format  |  1989-05-10  |  54KB

  1. Path: xanth!ames!oliveb!sun!swap!page
  2. From: page%swap@Sun.COM (Bob Page)
  3. Newsgroups: comp.sources.amiga
  4. Subject: v89i123:  mymenu - add custom menus to workbench strip
  5. Message-ID: <104016@sun.Eng.Sun.COM>
  6. Date: 10 May 89 04:31:56 GMT
  7. Sender: news@sun.Eng.Sun.COM
  8. Lines: 1854
  9. Approved: page@sun.com
  10.  
  11. Submitted-by: leadsv!laic!darin@pyramid.pyramid.com (Darin Johnson)
  12. Posting-number: Volume 89, Issue 123
  13. Archive-name: workbench/mymenu.1
  14.  
  15. Allows you to add custom menus to the workbench menu strip to run
  16. commonly used commands.
  17.  
  18. [binary was previously posted in comp.binaries.amiga v89i051.  ..bob]
  19.  
  20. # This is a shell archive.
  21. # Remove anything above and including the cut line.
  22. # Then run the rest of the file through 'sh'.
  23. # Unpacked files will be owned by you and have default permissions.
  24. #----cut here-----cut here-----cut here-----cut here----#
  25. #!/bin/sh
  26. # shar: SHell ARchive
  27. # Run the following text through 'sh' to create:
  28. #    DoRun.c
  29. #    Makefile
  30. #    Menu.c
  31. #    Mon.c
  32. #    MyMenu-Handler.c
  33. #    MyMenu.c
  34. #    MyMenu.conf
  35. #    MyMenu.doc
  36. #    MyMenu.h
  37. #    Parse.c
  38. #    README
  39. #    newbugs
  40. # This is archive 1 of a 1-part kit.
  41. # This archive created: Tue May  9 21:25:25 1989
  42. echo "extracting DoRun.c"
  43. sed 's/^X//' << \SHAR_EOF > DoRun.c
  44. X/* Copyright ) Darin Johnson, 1989 */
  45. X
  46. X/* DoRun.c -- I met her on a Monday, and my heart stood still... */
  47. X
  48. X#include <exec/types.h>
  49. X#include <exec/memory.h>
  50. X#include <libraries/dos.h>
  51. X#include <libraries/dosextens.h>
  52. X#include <intuition/intuition.h>
  53. X#include <workbench/icon.h>
  54. X#include <workbench/startup.h>
  55. X#include <workbench/workbench.h>
  56. X#include <functions.h>
  57. X#include "mymenu.h"
  58. X
  59. X#ifdef AZTEC_C
  60. X#define strlen _BUILTIN_strlen
  61. X#define strcpy _BUILTIN_strcpy
  62. X#endif
  63. X
  64. X#ifdef DO_PATH
  65. X#define CMDSIZ 256
  66. X#define CBUFSZ 80
  67. X#endif
  68. X
  69. Xextern struct Process *MyProcess;
  70. X
  71. X/* text to put into autorequesters */
  72. Xstruct IntuiText err_nocmd = { 0,1,JAM2, 20,10, NULL, 
  73. X    (UBYTE*)"MyMenu: can't execute command", NULL };
  74. Xstruct IntuiText err_nomem = { 0,1,JAM2, 20,10, NULL, 
  75. X    (UBYTE*)"MyMenu: out of memory!", NULL };
  76. Xstruct IntuiText err_noinfo = { 0,1,JAM2, 20,10, NULL, 
  77. X    (UBYTE*)"MyMenu: can't open info file", NULL };
  78. Xstruct IntuiText err_notool = { 0,1,JAM2, 20,10, NULL, 
  79. X    (UBYTE*)"MyMenu: not a tool or project", NULL };
  80. Xstruct IntuiText req_neg = { 0,1,JAM2, 7,3, NULL,
  81. X    (UBYTE*)"Aw, shucks", NULL };
  82. X
  83. X/* process a menu item */
  84. Xint run_item(item)
  85. X  struct ext_MenuItem *item;
  86. X{
  87. X  if (item->cmd) {
  88. X    if (item->type == 'C') {
  89. X      do_clirun(item->cmd, item->args);
  90. X    }
  91. X#ifdef DO_WB
  92. X    else if (item->type == 'W') {
  93. X      do_wbrun(item->cmd);
  94. X    }
  95. X#endif
  96. X  }
  97. X}
  98. X
  99. X#ifdef DO_PATH
  100. Xchar *FindIt();
  101. X#endif
  102. X
  103. X/* execute a CLI command */
  104. Xdo_clirun(cmd, args)
  105. X  char *cmd, *args;
  106. X{
  107. X  struct FileHandle *NilFh, *Open();
  108. X  register char *buf;
  109. X  register short siz;
  110. X
  111. X#ifdef DO_PATH
  112. X  cmd = FindIt(cmd);
  113. X#endif
  114. X  if (cmd==NULL) {
  115. X    AutoRequest(NULL, &err_nocmd, NULL, &req_neg, 0,0,300,60);
  116. X    return;
  117. X  }
  118. X
  119. X  siz = 32 + strlen(cmd);
  120. X  if (args)
  121. X    siz += strlen(args);
  122. X  buf = (char *)AllocMem(siz, MEMF_PUBLIC);
  123. X  if (buf==NULL) {
  124. X    AutoRequest(NULL, &err_nomem, NULL, &req_neg, 0,0,300,60);
  125. X    return;
  126. X  }
  127. X  strcpy(buf, "RUN <NIL: >NIL: \"");
  128. X  strcat(buf, cmd);
  129. X  strcat(buf, "\" <NIL: >NIL: ");
  130. X  if (args)
  131. X    strcat(buf, args);
  132. X    
  133. X  NilFh = Open("NIL:", MODE_NEWFILE);
  134. X  if (NilFh) {
  135. X    Execute(buf, NULL, NilFh);
  136. X    Close(NilFh);
  137. X  }
  138. X  FreeMem(buf, siz);
  139. X}
  140. X
  141. X/* procedures to support running WorkBench programs */
  142. X
  143. X#ifdef DO_WB
  144. Xextern int wb_cnt;
  145. Xextern struct MsgPort *wb_reply_port;
  146. X
  147. X/* create (and allocate) a copy of a string */
  148. Xchar *copystr(str) {
  149. X  char *tmpstr;
  150. X  if (!str)
  151. X    return NULL;
  152. X  tmpstr = (char *)AllocMem(strlen(str)+1, MEMF_PUBLIC);
  153. X  strcpy(tmpstr, str);
  154. X  return tmpstr;
  155. X}
  156. X
  157. X/* Free up space used by a workbench startup message.  Called whenever
  158. X   a workbench program replies to the startup message, and whenever
  159. X   do_wbrun() gets an error */
  160. Xwbfree(WBStartup)
  161. X  struct WBStartup *WBStartup;
  162. X{
  163. X  register BPTR lock;
  164. X  register int i;
  165. X  register char *cp;
  166. X  if (WBStartup != NULL) {
  167. X    if (WBStartup->sm_ArgList != NULL) {
  168. X      for (i=0; i<WBStartup->sm_NumArgs; i++) {
  169. X        if ((lock=WBStartup->sm_ArgList[i].wa_Lock) != NULL) {
  170. X          UnLock(lock);
  171. X    }
  172. X    if ((cp=WBStartup->sm_ArgList[i].wa_Name) != NULL)
  173. X      FreeMem(cp, strlen(cp)+1);
  174. X      }
  175. X      FreeMem(WBStartup->sm_ArgList,
  176. X      sizeof(struct WBArg)*WBStartup->sm_NumArgs);
  177. X    }
  178. X    if (WBStartup->sm_Segment != NULL) {
  179. X      UnLoadSeg(WBStartup->sm_Segment);
  180. X    }
  181. X    if ((cp=WBStartup->sm_ToolWindow) != NULL)
  182. X      FreeMem(cp, strlen(cp)+1);
  183. X    FreeMem(WBStartup, sizeof(struct WBStartup));
  184. X  }
  185. X}
  186. X
  187. X/* take the path passed, and split it into a lock and name,
  188. X   suitable for putting into a WBArg structure */
  189. Xsplit_path(path, dir_lock, name)
  190. X  char *path, **name;
  191. X  BPTR *dir_lock;
  192. X{
  193. X  register char *p;
  194. X  register BPTR lock;
  195. X  
  196. X  for (p=path, *name=path; *p; p++)
  197. X    if (*p == '/' || *p == ':')
  198. X      *name = p+1;
  199. X  lock = (BPTR)Lock(path, ACCESS_READ);
  200. X  if (lock) {
  201. X    *dir_lock = (BPTR)ParentDir(lock);
  202. X    UnLock(lock);
  203. X  } else {
  204. X    *dir_lock = (BPTR)DupLock(MyProcess->pr_CurrentDir);
  205. X  }
  206. X}
  207. X
  208. X/* load and run a workbench program */
  209. Xint do_wbrun(cmd)
  210. X  char *cmd;
  211. X{
  212. X  BPTR lock, oldlock;
  213. X  struct WBStartup *WBStartup;
  214. X  struct DiskObject *disk_object;
  215. X  char argc, *name, buf[128];
  216. X  char error;
  217. X    
  218. X  disk_object = WBStartup = NULL;
  219. X  lock = oldlock = NULL;
  220. X  name = NULL;
  221. X  error = TRUE;    /* assume the worst */
  222. X
  223. X    /* allocate the startup message */
  224. X  if ((WBStartup = (struct WBStartup *)AllocMem(sizeof(struct WBStartup),
  225. X              MEMF_PUBLIC|MEMF_CLEAR)) == NULL) {
  226. X    AutoRequest(NULL, &err_nomem, NULL, &req_neg, 0,0,300,60);
  227. X    return TRUE;    /* don't go to finish:, nothing allocated yet */
  228. X  }
  229. X#ifdef DO_PATH
  230. X  if ((cmd = FindIt(cmd)) == NULL)
  231. X    goto finish;
  232. X#endif
  233. X
  234. X    /* find the directory and name of the program to run */
  235. X  split_path(cmd, &lock, &name);
  236. X  if (lock == NULL) {
  237. X    AutoRequest(NULL, &err_nocmd, NULL, &req_neg, 0,0,300,60);
  238. X    goto finish;
  239. X  }
  240. X
  241. X    /* try to load in the .info file */
  242. X  oldlock = (BPTR)CurrentDir(lock);
  243. X  if ((disk_object = GetDiskObject(name)) == NULL) {
  244. X    AutoRequest(NULL, &err_noinfo, NULL, &req_neg, 0,0,300,60);
  245. X    goto finish;
  246. X  }
  247. X
  248. X    /* allocate the WBArgs - if we are a tool, we allocate one */
  249. X    /* of these, else two (one for tool, one for project)      */
  250. X  if (disk_object->do_Type == WBTOOL) {
  251. X    if ((WBStartup->sm_ArgList = (struct WBArg *)
  252. X    AllocMem(sizeof(struct WBArg), MEMF_PUBLIC|MEMF_CLEAR)) == NULL) {
  253. X      AutoRequest(NULL, &err_nomem, NULL, &req_neg, 0,0,300,60);
  254. X      goto finish;
  255. X    }
  256. X    WBStartup->sm_NumArgs = 1;
  257. X  } else if (disk_object->do_Type == WBPROJECT) {
  258. X    if ((WBStartup->sm_ArgList = (struct WBArg *)
  259. X    AllocMem(sizeof(struct WBArg)*2, MEMF_PUBLIC|MEMF_CLEAR)) == NULL) {
  260. X      AutoRequest(NULL, &err_nomem, NULL, &req_neg, 0,0,300,60);
  261. X      goto finish;
  262. X    }
  263. X    WBStartup->sm_NumArgs = 2;
  264. X      /* fill in arg #2 with the info we already have */
  265. X    WBStartup->sm_ArgList[1].wa_Lock = (BPTR)lock;
  266. X    WBStartup->sm_ArgList[1].wa_Name = copystr(name);
  267. X      /* now find the tool */
  268. X    strcpy(buf, disk_object->do_DefaultTool);
  269. X    split_path(buf, &lock, &name);
  270. X    FreeDiskObject(disk_object);
  271. X    CurrentDir(lock);
  272. X    if ((disk_object = GetDiskObject(name)) == NULL) {
  273. X      AutoRequest(NULL, &err_noinfo, NULL, &req_neg, 0,0,300,60);
  274. X      goto finish;
  275. X    }
  276. X      /* we have to have a tool at this point - or else */
  277. X    if (disk_object->do_Type != WBTOOL) {
  278. X      AutoRequest(NULL, &err_notool, NULL, &req_neg, 0,0,300,60);
  279. X      goto finish;
  280. X    }
  281. X  }
  282. X
  283. X    /* fill in arguments */
  284. X  WBStartup->sm_ArgList[0].wa_Lock = (BPTR)lock;
  285. X  WBStartup->sm_ArgList[0].wa_Name = copystr(name);
  286. X  
  287. X    /* initialize rest of startup message */
  288. X  WBStartup->sm_Message.mn_ReplyPort = wb_reply_port;
  289. X  WBStartup->sm_Message.mn_Length = sizeof(struct WBStartup);
  290. X  WBStartup->sm_Message.mn_Node.ln_Type = NT_MESSAGE;
  291. X  WBStartup->sm_ToolWindow = copystr(disk_object->do_ToolWindow);
  292. X
  293. X    /* get a decent stack size, there are a few progs that set this to zero */
  294. X  if (disk_object->do_StackSize < 4000)
  295. X    disk_object->do_StackSize = 4000;
  296. X
  297. X    /* load in the program */
  298. X  if ((WBStartup->sm_Segment = (BPTR)LoadSeg(name)) == NULL) {
  299. X    AutoRequest(NULL, &err_nocmd, NULL, &req_neg, 0,0,300,60);
  300. X    goto finish;
  301. X  }
  302. X
  303. X   /* create process */
  304. X  if ((WBStartup->sm_Process = (struct MsgPort *)CreateProc(name,
  305. X     0, WBStartup->sm_Segment, disk_object->do_StackSize)) == NULL) {
  306. X    AutoRequest(NULL, &err_nocmd, NULL, &req_neg, 0,0,300,60);
  307. X    goto finish;
  308. X  }
  309. X    /* everything's ok -- start 'er up */
  310. X  PutMsg(WBStartup->sm_Process, WBStartup);
  311. X  error = FALSE;
  312. X  wb_cnt++;    /* keep track of unreplied startup messages */
  313. Xfinish:
  314. X  if (disk_object) FreeDiskObject(disk_object);
  315. X  if (oldlock) CurrentDir(oldlock);
  316. X  if (error)
  317. X    wbfree(WBStartup);
  318. X  return error;
  319. X}
  320. X#endif
  321. X
  322. X#ifdef DO_PATH
  323. X/* This section is largely taken from RunBack
  324. X  (which was largely taken from which.c by Carolyn Scheppner).
  325. X  This handles path searching.
  326. X*/
  327. X
  328. X/***** currently these routines can cause guru's
  329. X       Run a workbench program, and then run a program that
  330. X       uses the path searching - often causes a Guru, but can't
  331. X       tell why.  If the wbfree() does NOT free its locks, then
  332. X       it doesn't guru.
  333. X*****/
  334. X
  335. Xstatic char sbuf[CMDSIZ];
  336. X
  337. X/* search for a command in our path */
  338. Xchar *FindIt(command)
  339. X  char *command;
  340. X{
  341. X  BOOL getPath();
  342. X  struct Path *path;
  343. X  struct FileInfoBlock *fib;
  344. X  BPTR lock, startcd;
  345. X  BOOL Found, InitialCD;
  346. X
  347. X     /* Were we given full path in command name (':' in name) ? */
  348. X  {
  349. X    register char *p;
  350. X    for (p=command; *p; p++) {
  351. X      if (*p == ':') {
  352. X        lock = (BPTR)Lock(command,ACCESS_READ);
  353. X    if (lock==NULL)
  354. X      return NULL;        /* command not found */
  355. X    UnLock(lock);
  356. X        return command;
  357. X      }
  358. X    }
  359. X  }
  360. X  
  361. X    /* allocate this for Examine() calls */ 
  362. X  fib = (struct FileInfoBlock *)
  363. X    AllocMem(sizeof(struct FileInfoBlock), MEMF_PUBLIC|MEMF_CLEAR);
  364. X  if (fib == NULL)
  365. X    return NULL;
  366. X    
  367. X    /* Check current directory */
  368. X  Found = getPath(command, fib, sbuf);
  369. X
  370. X    /* Check along paths */
  371. X  if (!Found) {
  372. X    InitialCD = TRUE;
  373. X
  374. X    for (path = MM->CLI_path; (path) && (!Found); path = path->path_Next) {
  375. X        /* CD to each path */
  376. X      lock = (BPTR)CurrentDir(path->path_Lock);
  377. X      if (InitialCD) {
  378. X        startcd = lock; InitialCD = FALSE;
  379. X      }
  380. X        /* See if command is there */
  381. X      Found = getPath(command, fib, sbuf);
  382. X    }
  383. X      /* If we CD'd anywhere, restore initial CD */
  384. X    if (!InitialCD) 
  385. X      CurrentDir(startcd);
  386. X  }
  387. X
  388. X    /* Check C: */
  389. X  if (!Found) {
  390. X    char cbuf[CBUFSZ];
  391. X    strcpy(cbuf,"C:");
  392. X    strcpy(&cbuf[2], command);
  393. X    Found = getPath(cbuf, fib, sbuf);
  394. X  }
  395. X
  396. X    /* Free fib */
  397. X  if (fib != NULL)
  398. X    FreeMem(fib, sizeof(struct FileInfoBlock));
  399. X
  400. X  if (Found)
  401. X    return(sbuf);
  402. X  else
  403. X    return(NULL);
  404. X}
  405. X
  406. X/* see if command is in current directory, if so, return path name
  407. X   in 'buf' */
  408. XBOOL
  409. XgetPath(command,fib,buf)
  410. X  char *command;
  411. X  struct FileInfoBlock *fib;
  412. X  char *buf;
  413. X{
  414. X  BPTR lock;
  415. X  BOOL success = FALSE;
  416. X  if (lock = (BPTR)Lock(command, ACCESS_READ)) {
  417. X    if (Examine(lock, fib)) {
  418. X      buildPath(lock, fib, buf);
  419. X      success = TRUE;
  420. X    }
  421. X    UnLock(lock);
  422. X  }
  423. X  return(success);
  424. X}
  425. X
  426. X/* builds up a path name from 'inlock' and returns it in 'buf' */
  427. XbuildPath(inlock,fib,buf)
  428. X  BPTR inlock;
  429. X  struct FileInfoBlock *fib;
  430. X  char *buf;
  431. X{
  432. X  int i;
  433. X  BPTR lock, oldlock;
  434. X  buf[0] = NULL;
  435. X  lock = inlock;
  436. X
  437. X    /* follow path up, building up name as we go */
  438. X  while (lock) {
  439. X    if (Examine(lock, fib)) {
  440. X      if (fib->fib_FileName[0] > ' ') {
  441. X        if (buf[0]) insert(buf,"/");
  442. X        insert(buf,fib->fib_FileName);
  443. X      }
  444. X    }
  445. X    oldlock = lock;
  446. X    lock = (BPTR)ParentDir(lock);
  447. X      /* make sure we don't unlock the lock passed to us */
  448. X    if (oldlock != inlock)
  449. X       UnLock(oldlock);
  450. X  }
  451. X
  452. X    /* fix up path name */
  453. X  if (fib->fib_FileName[0] > ' ') {
  454. X    register char *p;
  455. X    for (p=buf; *p; p++) {
  456. X      if (*p == '/') {
  457. X        *p = ':';
  458. X    break;
  459. X      }
  460. X    }
  461. X  } else
  462. X    insert(buf,"RAM:");    /* why? */
  463. X}
  464. X
  465. X/* insert 's' at the beginning of 'buf' */
  466. Xinsert(buf,s)
  467. X  char *buf,*s;
  468. X{
  469. X  char tmp[CMDSIZ];
  470. X  strcpy(tmp, buf);
  471. X  strcpy(buf, s);
  472. X  strcpy(&buf[strlen(s)], tmp);
  473. X}
  474. X#endif
  475. SHAR_EOF
  476. echo "extracting Makefile"
  477. sed 's/^X//' << \SHAR_EOF > Makefile
  478. XALL: MyMenu MyMenu-Handler
  479. X
  480. XMyMenu: MyMenu.o Menu.o Parse.o
  481. X    ln -o MyMenu +Q MyMenu.o Menu.o Parse.o -lc32
  482. X
  483. XMyMenu.o: MyMenu.c MyMenu.h
  484. X    cc +L +m MyMenu.c
  485. X
  486. XMyMenu-Handler: MyMenu-Handler.o Mon.o DoRun.o
  487. X    ln -o MyMenu-Handler +Q MyMenu-Handler.o Mon.o DoRun.o -lc32
  488. X
  489. XMyMenu-Handler.o: MyMenu-Handler.c MyMenu.h
  490. X    cc +L MyMenu-Handler.c
  491. X
  492. XDoRun.o: DoRun.c MyMenu.h
  493. X    cc +L DoRun.c
  494. X
  495. XMon.o:    Mon.c MyMenu.h
  496. X    cc +L Mon.c
  497. X
  498. XMenu.o:    Menu.c MyMenu.h
  499. X    cc +L +m Menu.c
  500. X
  501. XParse.o: Parse.c MyMenu.h
  502. X    cc +L +m Parse.c
  503. SHAR_EOF
  504. echo "extracting Menu.c"
  505. sed 's/^X//' << \SHAR_EOF > Menu.c
  506. X/* Copyright ) Darin Johnson, 1989 */
  507. X
  508. X#include <exec/memory.h>
  509. X#include <graphics/text.h>
  510. X#include <graphics/gfxbase.h>
  511. X#include <intuition/intuition.h>
  512. X#include <clib/macros.h>
  513. X#include <functions.h>
  514. X#include "MyMenu.h"
  515. X
  516. XBYTE *copystr();
  517. X
  518. Xunsigned long mnum, inum, snum, menu_num;
  519. Xstruct ext_MenuItem *tail_list;
  520. XUWORD font_width, font_height;
  521. XUBYTE menu_pen;        /* pen number for newly created items */
  522. X
  523. Xextern struct GfxBase *GfxBase;
  524. X
  525. Xstruct Menu *mptr;
  526. Xstruct MenuItem *iptr, *sptr;
  527. X
  528. X/* clean things up and initialize */
  529. Xstart_menu() {
  530. X  MM->my_menu = NULL;
  531. X  menu_pen = 0;    /* default */
  532. X  MM->item_list = tail_list = NULL;
  533. X  font_width = GfxBase->DefaultFont->tf_XSize;
  534. X  font_height = GfxBase->DefaultFont->tf_YSize;
  535. X}
  536. X
  537. X/* clean up widths and other info now that menu is all built */
  538. Xend_menu() {
  539. X  UWORD maxw, smaxw, txtw, top, stop, left;
  540. X  
  541. X  ULONG ilock;
  542. X  if (MM->prev_menu) {
  543. X    ilock = LockIBase(0L);
  544. X    left = MM->prev_menu->LeftEdge + MM->prev_menu->Width + SEPARATE;
  545. X    UnlockIBase(ilock);
  546. X  }
  547. X  for (mptr = MM->my_menu; mptr; mptr=mptr->NextMenu) {
  548. X    mptr->LeftEdge = left;
  549. X    maxw = mptr->Width = (strlen(mptr->MenuName)+1) * font_width;
  550. X    maxw += SEPARATE;
  551. X    left += maxw;
  552. X    top = 0;
  553. X      /* determine max width */
  554. X    for (iptr = mptr->FirstItem; iptr; iptr=iptr->NextItem) {
  555. X      iptr->TopEdge = top;
  556. X      top += iptr->Height;
  557. X      txtw = IntuiTextLength(iptr->ItemFill);
  558. X      if (iptr->Flags & COMMSEQ)
  559. X        txtw += COMMWIDTH+font_width+4;
  560. X      if (txtw > maxw)
  561. X        maxw = txtw;
  562. X    }
  563. X    for (iptr = mptr->FirstItem; iptr; iptr=iptr->NextItem) {
  564. X      iptr->Width = maxw;
  565. X      stop = smaxw = 0;
  566. X      for (sptr=iptr->SubItem; sptr; sptr=sptr->NextItem) {
  567. X        sptr->LeftEdge = maxw;
  568. X        sptr->TopEdge = stop;
  569. X        stop += sptr->Height;
  570. X        txtw = IntuiTextLength(sptr->ItemFill);
  571. X        if (sptr->Flags & COMMSEQ)
  572. X          txtw += COMMWIDTH+font_width+4;
  573. X        if (txtw > smaxw)
  574. X          smaxw = txtw;
  575. X      }
  576. X      for (sptr=iptr->SubItem; sptr; sptr=sptr->NextItem)
  577. X        sptr->Width = smaxw;
  578. X    }
  579. X  }
  580. X}
  581. X
  582. X/* allocate and initialize a new menu */
  583. Xstruct Menu *new_menu(menustr)
  584. X  char *menustr;
  585. X{
  586. X  struct Menu *menu;
  587. X  menu = (struct Menu *)
  588. X    AllocMem(sizeof(struct Menu), MEMF_PUBLIC|MEMF_CLEAR);
  589. X  menu->MenuName = copystr(menustr);
  590. X  menu->Flags = MENUENABLED;
  591. X  menu->NextMenu = NULL;
  592. X  menu->FirstItem = NULL;
  593. X  menu->TopEdge = menu->Height = 0;
  594. X  return menu;
  595. X}
  596. X
  597. X/* Find a menu.  If not found, create a new one */
  598. Xstruct Menu *get_menu(menustr)
  599. X  char *menustr;
  600. X{
  601. X  struct Menu *menu, *prev;
  602. X  mnum = menu_num + 1;
  603. X  if (MM->my_menu == NULL)        /* our menu strip */
  604. X    menu = MM->my_menu = new_menu(menustr);
  605. X  else {
  606. X    for (menu=MM->my_menu; menu; menu=menu->NextMenu) {
  607. X      if (!strcmp(menustr, (char *)menu->MenuName))
  608. X        break;    /* already here */
  609. X      prev = menu;
  610. X      mnum++;
  611. X    }
  612. X    if (menu == NULL)
  613. X      menu = prev->NextMenu = new_menu(menustr);
  614. X  }
  615. X  return menu;
  616. X}
  617. X
  618. X/* create and initialize a new menu item */
  619. Xstruct MenuItem *new_item(itemstr)
  620. X  char *itemstr;
  621. X{
  622. X  struct MenuItem *item;
  623. X  struct IntuiText *it;
  624. X    /* notice that we allocate extra space */
  625. X  item = (struct MenuItem *)
  626. X    AllocMem(sizeof(struct ext_MenuItem), MEMF_PUBLIC|MEMF_CLEAR);
  627. X  it = (struct IntuiText *)
  628. X    AllocMem(sizeof(struct IntuiText), MEMF_PUBLIC|MEMF_CLEAR);
  629. X  item->NextItem = item->SubItem = NULL;
  630. X  item->SelectFill = NULL;
  631. X  item->NextSelect = 0;
  632. X  item->Height = font_height + 1;
  633. X  item->LeftEdge = item->TopEdge = item->MutualExclude = 0;
  634. X  item->Flags = ITEMTEXT+HIGHCOMP+ITEMENABLED;
  635. X  it->FrontPen = menu_pen;
  636. X  it->BackPen = AUTOBACKPEN;
  637. X  it->LeftEdge = it->TopEdge = 1;
  638. X  it->ITextFont = NULL;
  639. X  it->NextText = NULL;
  640. X  it->DrawMode = JAM2;
  641. X  it->IText = (UBYTE*)copystr(itemstr);
  642. X  item->ItemFill = (APTR)it;
  643. X  return item;
  644. X}
  645. X
  646. X/* find a menu item, if not found, create a new one */
  647. Xstruct MenuItem *get_item(menustr, itemstr)
  648. X  char *menustr, *itemstr;
  649. X{
  650. X  struct Menu *menu;
  651. X  struct MenuItem *item, *prev;
  652. X  menu = get_menu(menustr);
  653. X  inum = 0;
  654. X  if (menu->FirstItem == NULL)
  655. X    item = menu->FirstItem = new_item(itemstr);
  656. X  else {
  657. X    for (item=menu->FirstItem; item; item=item->NextItem) {
  658. X      if (!strcmp(itemstr, ((struct IntuiText *)item->ItemFill)->IText))
  659. X        break;    /* already here */
  660. X      prev = item;
  661. X      inum++;
  662. X    }
  663. X    if (item == NULL)
  664. X      item = prev->NextItem = new_item(itemstr);
  665. X  }
  666. X  return item;
  667. X}
  668. X
  669. X#define EITEM ((struct ext_MenuItem *)item)
  670. X
  671. X/* create a new menu item (or sub item) */
  672. Xstruct ext_MenuItem *add_menu(menustr, itemstr, substr, comm)
  673. X  char *menustr, *itemstr, *substr, comm;
  674. X{
  675. X  struct MenuItem *item, *sub, *prev;
  676. X  if (!itemstr)
  677. X    return NULL;    /* oops */
  678. X  item = get_item(menustr, itemstr);    /* get (or create) the item */
  679. X  if (substr && *substr) {
  680. X    snum = 0;
  681. X    if (item->SubItem == NULL)
  682. X      sub = item->SubItem = new_item(substr);    /* get the sub-item */
  683. X    else {
  684. X      for (sub=item->SubItem; sub; sub=sub->NextItem) {
  685. X        if (!strcmp(substr, (char *)sub->ItemFill))
  686. X          break;    /* duplicate */
  687. X        prev = sub;
  688. X    snum++;
  689. X      }
  690. X      if (sub == NULL)
  691. X        sub = prev->NextItem = new_item(substr);
  692. X    }
  693. X    item = sub;
  694. X  } else
  695. X    snum = NOSUB;
  696. X  if (comm) {
  697. X    item->Command = comm;
  698. X    item->Flags |= COMMSEQ;
  699. X  }
  700. X    /* fill in our private fields */
  701. X  EITEM->id = SHIFTMENU(mnum)|SHIFTITEM(inum)|SHIFTSUB(snum);
  702. X  EITEM->cmd = EITEM->args = NULL;
  703. X  EITEM->type = NULL;
  704. X    /* stick onto item_list */
  705. X  EITEM->next_item = NULL;
  706. X  if (MM->item_list==NULL)
  707. X    MM->item_list = EITEM;
  708. X  else
  709. X    tail_list->next_item = EITEM;
  710. X  tail_list = EITEM;
  711. X  return EITEM;
  712. X}
  713. X
  714. X/* free up memory used by a menu item */
  715. Xfree_item(item)
  716. X  struct ext_MenuItem *item;
  717. X{
  718. X  struct IntuiText *it;
  719. X  it = (struct IntuiText *)item->MenuItem.ItemFill;
  720. X  FreeMem(it->IText, strlen(it->IText)+1);
  721. X  FreeMem(it, sizeof(struct IntuiText));
  722. X  if (item->cmd)
  723. X    FreeMem(item->cmd, strlen(item->cmd)+1);
  724. X  if (item->args)
  725. X    FreeMem(item->args, strlen(item->args)+1);
  726. X  FreeMem(item, sizeof(struct ext_MenuItem));
  727. X}
  728. X
  729. X/* free up all space taken up by our menus */
  730. Xfree_menus() {
  731. X  struct Menu *mtmp;
  732. X  struct MenuItem *itmp;
  733. X
  734. X  mptr = MM->my_menu;
  735. X  MM->my_menu = NULL;
  736. X  while (mptr) {
  737. X    iptr = mptr->FirstItem;
  738. X    while (iptr) {
  739. X      sptr = iptr->SubItem;
  740. X      while (sptr) {
  741. X        itmp = sptr;
  742. X    sptr = sptr->NextItem;
  743. X    free_item(itmp);
  744. X      }
  745. X      itmp = iptr;
  746. X      iptr = iptr->NextItem;
  747. X      free_item(itmp);
  748. X    }
  749. X    mtmp = mptr;
  750. X    mptr = mptr->NextMenu;
  751. X    FreeMem(mtmp->MenuName, strlen(mtmp->MenuName)+1);
  752. X    FreeMem(mtmp, sizeof(struct Menu));
  753. X  }
  754. X}
  755. SHAR_EOF
  756. echo "extracting Mon.c"
  757. sed 's/^X//' << \SHAR_EOF > Mon.c
  758. X/* Copyright ) Darin Johnson, 1989 */
  759. X
  760. X/* This file has routines to allow us to 'monitor' an Intuition port */
  761. X
  762. X/* What happens, is that we create a port, myPort, and set things up */
  763. X/* so that GetMsg works normally for myPort, and the original port,  */
  764. X/* winPort.  However, PutMsg to myPort will put the new message      */
  765. X/* on winPort, and vice-versa.  Basically, the heads of both message */
  766. X/* lists are normal, but the two tails have been swapped.  Since     */
  767. X/* GetMsg uses the head of the list, it acts normally.  PutMsg uses  */
  768. X/* the tail of the list, so it acts differently.  (the sigBit and    */
  769. X/* sigTasks have also been swapped)                                  */
  770. X
  771. X/* What this means, is that anything PutMsg'ed to the winPort, will  */
  772. X/* signal us, and we can GetMsg it.  When we are finished looking at */
  773. X/* that message, we can give it to winPort by PutMsg'ing to myPort.  */
  774. X
  775. X#include <exec/ports.h>
  776. X#include <libraries/dos.h>
  777. X#include <libraries/dosextens.h>
  778. X#include <intuition/intuitionbase.h>
  779. X#include <devices/inputevent.h>
  780. X#include <functions.h>
  781. X#include "mymenu.h"
  782. X
  783. X#ifdef DO_WB
  784. Xextern struct MsgPort *wb_reply_port;
  785. Xextern int wb_cnt;
  786. X#endif
  787. X
  788. Xstatic struct MsgPort *winPort;
  789. Xstatic struct List *winMsgList;
  790. Xstatic LONG winSignal, our_signal;
  791. Xstatic LONG winMask;
  792. Xstatic BYTE orig_pri;
  793. X
  794. X/* our port */
  795. Xstatic struct MsgPort myPort =
  796. X{
  797. X   {NULL, NULL, NT_MSGPORT, 0, NULL},
  798. X   PA_SIGNAL,
  799. X   0,
  800. X   NULL,
  801. X   {NULL, NULL, NULL, NT_MESSAGE, 0}
  802. X};
  803. X
  804. Xstatic struct List *myMsgList = &(myPort.mp_MsgList);
  805. X
  806. X/* fiddle with the two ports, setting things up */
  807. Xmake_MsgPort()
  808. X{
  809. X  Forbid();
  810. X    /* get the info we need */
  811. X  winPort    = MM->WBWindow->UserPort;
  812. X  winMsgList = &(winPort->mp_MsgList);
  813. X  winSignal  = winPort->mp_SigBit;
  814. X  winMask    = 1L << winSignal;
  815. X
  816. X    /* setup our port */  
  817. X  myPort.mp_SigBit    = winSignal;
  818. X  myPort.mp_SigTask   = winPort->mp_SigTask;
  819. X
  820. X    /* flip things around */
  821. X  winPort->mp_SigTask = MM->handler_task;
  822. X  myMsgList->lh_Head = (struct Node *)&(winMsgList->lh_Tail);
  823. X  myMsgList->lh_TailPred = winMsgList->lh_TailPred;
  824. X  winMsgList->lh_TailPred = (struct Node *)&(myMsgList->lh_Head);
  825. X  myMsgList->lh_TailPred->ln_Succ = (struct Node *)&(myMsgList->lh_Tail);
  826. X
  827. X  Permit();
  828. X
  829. X    /* prevent deadlocks */
  830. X  orig_pri = SetTaskPri(MM->handler_task,
  831. X        myPort.mp_SigTask->tc_Node.ln_Pri+1);
  832. X}
  833. X
  834. X/* Restore things the way they were before make_MsgPort()           */
  835. X/* Note that we don't refer to winPort.  This is because we         */
  836. X/* may have had someone else 'monitor' this port (such as MonIDCMP) */
  837. X/* besides us.                                                      */
  838. Xdel_MsgPort() {
  839. X  struct Message *tmpMsg;
  840. X  struct MsgPort *tmpPort;
  841. X  
  842. X  Forbid();
  843. X    /* clean out our list */
  844. X  while ((tmpMsg = GetMsg(&myPort)) != NULL) PutMsg(&myPort, tmpMsg);
  845. X
  846. X     /* find MsgPort that myMsgList->lh_Head belongs to */
  847. X     /*      (the port we've been PutMsg'ing to)        */
  848. X  tmpPort = (struct MsgPort *) (
  849. X    (UBYTE*) &myPort - (UBYTE*) &(myPort.mp_MsgList.lh_Tail)
  850. X    + (UBYTE*)myMsgList->lh_Head);
  851. X
  852. X    /* restore things */
  853. X  myMsgList->lh_Head->ln_Pred = myMsgList->lh_TailPred;
  854. X  myMsgList->lh_TailPred->ln_Succ = myMsgList->lh_Head;
  855. X  tmpPort->mp_SigTask = myPort.mp_SigTask;
  856. X  Permit();
  857. X  
  858. X  SetTaskPri(MM->handler_task, orig_pri);
  859. X}
  860. X
  861. X/* do all appropriate initialization of monitor */
  862. XBOOL setup_mon()
  863. X{
  864. X  make_MsgPort();
  865. X    /* we need to allocate the same signal, so that it doesn't get
  866. X       allocated to something else, messing us up */
  867. X  our_signal = AllocSignal(winSignal);
  868. X  if (our_signal != winSignal) {
  869. X    finish_mon();
  870. X    return FALSE;
  871. X  }
  872. X  return TRUE;
  873. X}
  874. X
  875. X/* clean up everything */
  876. Xfinish_mon() {
  877. X  del_MsgPort();
  878. X  FreeSignal(our_signal);
  879. X}
  880. X
  881. X/* See if we handle this event.  If so, return ext_MenuItem structure */
  882. Xstruct ext_MenuItem *
  883. Xmatch_item(Class, Code)
  884. X  ULONG Class;
  885. X  USHORT Code;
  886. X{
  887. X  register struct ext_MenuItem *tmp;
  888. X  if (Class != MENUPICK || Code == MENUNULL)
  889. X    return NULL;
  890. X  for (tmp = MM->item_list; tmp; tmp=tmp->next_item)
  891. X    if (tmp->id == Code)
  892. X      return tmp;
  893. X  return NULL;
  894. X}
  895. X
  896. X/* The actual monitor.  Just keep waiting for messages, and acting on them */
  897. X/* Note that if we don't use a certain IDCMP message, we PutMsg it to get  */
  898. X/* it back to the window it was meant for.                                 */
  899. Xmonitor()
  900. X{
  901. X  register struct IntuiMessage *msg;
  902. X  register void *item;
  903. X  register ULONG mask, wb_mask;
  904. X
  905. X#ifdef DO_WB
  906. X  winMask |= (wb_mask = (1L << wb_reply_port->mp_SigBit));
  907. X#endif
  908. X
  909. X  winMask |= SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D;
  910. X
  911. X  while (TRUE) {
  912. X    mask = Wait(winMask);
  913. X    if (mask & SIGBREAKF_CTRL_C) {
  914. X    /* caught ^C, time to close up */
  915. X      break;
  916. X    }
  917. X    if (mask & SIGBREAKF_CTRL_D) {
  918. X        /* reparse menus */
  919. X      del_menu_strip();
  920. X      Signal(MM->parent_task, (1 << MM->parent_sig));
  921. X      Wait(SIGBREAKF_CTRL_D);
  922. X      add_menu_strip();
  923. X      continue;
  924. X    }
  925. X#ifdef DO_WB
  926. X    if (mask & wb_mask) {
  927. X        /* caught a reply from a WorkBench program exitting */
  928. X      register struct Message *wb_msg;
  929. X      while ((wb_msg = GetMsg(wb_reply_port)) != NULL) {
  930. X        wbfree(wb_msg);
  931. X    wb_cnt = (wb_cnt>0 ? (wb_cnt-1) : 0);
  932. X      }
  933. X      continue;
  934. X    }
  935. X#endif
  936. X      /* if we got here, we have an IDCMP message */
  937. X    while ((msg = (struct IntuiMessage *)GetMsg(&myPort)) != NULL) {
  938. X          /* check if we deal with this or not */
  939. X      if ((item=(void *)match_item(msg->Class, msg->Code))!=NULL) {
  940. X        ReplyMsg(msg);        /* always reply */
  941. X        run_item(item);        /* run the indicated program */
  942. X      } else {
  943. X        PutMsg(&myPort, msg);    /* pass on to original destination */
  944. X      }
  945. X    }
  946. X  }
  947. X}
  948. SHAR_EOF
  949. echo "extracting MyMenu-Handler.c"
  950. sed 's/^X//' << \SHAR_EOF > MyMenu-Handler.c
  951. X/* Copyright ) Darin Johnson, 1989 */
  952. X/*                                 */
  953. X/* Permission is granted to use    */
  954. X/* this program and to freely copy */
  955. X/* it and/or source code as long   */
  956. X/* as these notices remain.        */
  957. X/* No charges for these copies may */
  958. X/* be made, except for handling    */
  959. X/* and distribution fees.          */
  960. X
  961. X/* This is the main process for MyMenu.  This gets loaded and run in the */
  962. X/* background by MyMenu.  When started, it finishes initializing itself, */
  963. X/* and starts monitoring the WorkBench IDCMP port.  If any messages show */
  964. X/* up that we are interested in, we run them as a CLI or WorkBench       */
  965. X/* process.  We don't do any memory allocation or cleanup and leave that */
  966. X/* all to MyMenu (in order to save some space).  Communication with      */
  967. X/* MyMenu is done via a public port - never used as a port, but it holds */
  968. X/* "global" variables.                                                   */
  969. X
  970. X#include <exec/types.h>
  971. X#include <intuition/intuition.h>
  972. X#include <libraries/dos.h>
  973. X#include <libraries/dosextens.h>
  974. X#include <workbench/icon.h>
  975. X#include <functions.h>
  976. X#include "mymenu.h"
  977. X
  978. Xstatic char *copyright = "Copyright ) Darin Johnson, 1989";
  979. X
  980. Xstruct IntuitionBase *IntuitionBase;
  981. X
  982. X#ifdef DO_WB
  983. Xstruct IconBase *IconBase;    /* already defined in Manx C */
  984. X#endif
  985. X
  986. Xstruct MMData *MM;        /* data shared with other tasks */
  987. Xstruct Process *MyProcess;
  988. X#ifdef DO_WB
  989. Xint wb_cnt;            /* number of wb processes run */
  990. Xstruct MsgPort *wb_reply_port;    /* replies from terminating WB processes */
  991. X#endif
  992. X
  993. X#ifdef DO_WB
  994. X  /* error messages */
  995. Xstruct IntuiText wb_open_msg_5 = { 3,1,JAM2,24,36,NULL,
  996. X    (UBYTE*)"Do you REALLY want to quit now?", NULL };
  997. Xstruct IntuiText wb_open_msg_4 = { 0,1,JAM2,7,28,NULL,
  998. X    (UBYTE*)"the program finishes after MyMenu.", &wb_open_msg_5 };
  999. Xstruct IntuiText wb_open_msg_3 = { 0,1,JAM2,7,20,NULL,
  1000. X    (UBYTE*)"still be open.  This can cause a crash if", &wb_open_msg_4 };
  1001. Xstruct IntuiText wb_open_msg_2 = { 0,1,JAM2,7,12,NULL,
  1002. X    (UBYTE*)"A WorkBench program started by MyMenu may", &wb_open_msg_3 };
  1003. Xstruct IntuiText wb_open_msg = { 3,1,JAM2,142,4,NULL,
  1004. X    (UBYTE*)"WARNING!!", &wb_open_msg_2 };
  1005. Xstruct IntuiText true_msg = { 0,1,JAM2,7,3,NULL,
  1006. X    (UBYTE*)"Yes, quit MyMenu", NULL };
  1007. Xstruct IntuiText false_msg = { 0,1,JAM2,7,3,NULL,
  1008. X    (UBYTE*)"No! I didn't mean it", NULL };
  1009. X#endif
  1010. X
  1011. X/* returns an error to MyMenu if we get one during initialization */
  1012. Xerror(code)
  1013. Xchar code;
  1014. X{
  1015. X  MM->error_code = code;
  1016. X  if (IntuitionBase)
  1017. X    CloseLibrary(IntuitionBase);
  1018. X#ifdef DO_WB
  1019. X  if (IconBase)
  1020. X    CloseLibrary(IconBase);
  1021. X#endif
  1022. X    /* coordinate with add_handler() in MyMenu */
  1023. X  Signal(MM->parent_task, 1 << MM->parent_sig);
  1024. X    /* now coordinate with remove_handler() in MyMenu */
  1025. X  Wait(SIGBREAKF_CTRL_C);    /* wait for parent */
  1026. X  Signal(MM->parent_task, 1 << MM->parent_sig);  
  1027. X  _exit(0);
  1028. X}
  1029. X
  1030. X/* add personalized menus to menustrip */
  1031. Xadd_menu_strip() {
  1032. X  struct Menu *menu_strip;
  1033. X  ULONG ilock;
  1034. X  menu_strip = MM->WBWindow->MenuStrip;
  1035. X  ilock = LockIBase(0L);
  1036. X  ClearMenuStrip(MM->WBWindow);
  1037. X  MM->prev_menu->NextMenu = MM->my_menu;
  1038. X  SetMenuStrip(MM->WBWindow, menu_strip);
  1039. X  UnlockIBase(ilock);
  1040. X}
  1041. X
  1042. X/* remove our personalized menus from menustrip */
  1043. Xdel_menu_strip() {
  1044. X  struct Menu *menu_strip;
  1045. X  ULONG ilock;
  1046. X  menu_strip = MM->WBWindow->MenuStrip;
  1047. X  ilock = LockIBase(0L);
  1048. X  ClearMenuStrip(MM->WBWindow);
  1049. X  MM->prev_menu->NextMenu = NULL;
  1050. X  SetMenuStrip(MM->WBWindow, menu_strip);
  1051. X  UnlockIBase(ilock);
  1052. X}
  1053. X
  1054. X/* main program - initialize and start up monitor */
  1055. X_main() {
  1056. X    /* find data set up by parent */
  1057. X  MM = (struct MMData *)FindPort(MYMENU_NAME);
  1058. X  if (!MM)
  1059. X    _exit(0);    /* some one ran us directly, bail out */
  1060. X
  1061. X    /* finish initialization */
  1062. X  MM->handler_task = FindTask(NULL);
  1063. X  MyProcess = (struct Process *)MM->handler_task;
  1064. X  MyProcess->pr_ConsoleTask = NULL;
  1065. X  MyProcess->pr_CLI = NULL;
  1066. X  MyProcess->pr_WindowPtr = (APTR)-1;    /* disable requesters for FindIt() */
  1067. X  MyProcess->pr_CurrentDir = NULL;
  1068. X
  1069. X    /* open necessary libraries */  
  1070. X  IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 0);
  1071. X  if (IntuitionBase == NULL)
  1072. X    error(ERR_LIB);
  1073. X#ifdef DO_WB
  1074. X  IconBase = (struct IconBase *)OpenLibrary(ICONNAME, 0);
  1075. X  if (IconBase == NULL)
  1076. X    error(ERR_LIB);
  1077. X#endif
  1078. X
  1079. X  if (!MM->WBWindow)
  1080. X    error(ERR_WIN);
  1081. X  if (!setup_mon())
  1082. X    error(ERR_MON);
  1083. X
  1084. X  MM->error_code = ERR_OK;
  1085. X
  1086. X    /* signal parent that we're fully weaned */
  1087. X  Signal(MM->parent_task, 1 << MM->parent_sig);
  1088. X
  1089. X  add_menu_strip();
  1090. X
  1091. X#ifdef DO_WB
  1092. X  wb_cnt = 0;
  1093. X    /* create port AFTER setup_mon() so we don't get same signal */
  1094. X  wb_reply_port = CreatePort(WBPORT_NAME, 0);
  1095. X  NewList(&wb_reply_port->mp_MsgList);    /* is this necessary? */
  1096. X#endif
  1097. X
  1098. Xrestart:
  1099. X    monitor();
  1100. X#ifdef DO_WB
  1101. X      /* see if we can leave gracefully */
  1102. X      /* we don't want to terminate and then have a WB reply message */
  1103. X    if ((wb_cnt > 0) && (AutoRequest(NULL,&wb_open_msg,
  1104. X                &true_msg,&false_msg,0,0,370,80)==FALSE))
  1105. X    {
  1106. X      MM->error_code = ERR_WB_OPEN;
  1107. X      Signal(MM->parent_task, 1 << MM->parent_sig);  
  1108. X      goto restart;
  1109. X    }
  1110. X#endif
  1111. X
  1112. X    /* clean everything up */
  1113. X  MM->error_code = ERR_OK;    /* let parent know that we finished up */
  1114. X  finish_mon();
  1115. X
  1116. X  del_menu_strip();
  1117. X  CloseLibrary(IntuitionBase);
  1118. X#ifdef DO_WB
  1119. X  CloseLibrary(IconBase);
  1120. X#endif
  1121. X
  1122. X    /* Forbid until we terminate, so that we don't get UnLoadSeg'ed to soon */
  1123. X  Forbid();
  1124. X
  1125. X#ifdef DO_WB
  1126. X  {
  1127. X    register struct Message *msg;
  1128. X    while ((msg=GetMsg(wb_reply_port))!=0)
  1129. X      wbfree(msg);
  1130. X    DeletePort(wb_reply_port);
  1131. X  }
  1132. X#endif
  1133. X
  1134. X    /* signal parent that we are done */
  1135. X  Signal(MM->parent_task, 1 << MM->parent_sig);  
  1136. X}
  1137. SHAR_EOF
  1138. echo "extracting MyMenu.c"
  1139. sed 's/^X//' << \SHAR_EOF > MyMenu.c
  1140. X/* Copyright ) Darin Johnson, 1989 */
  1141. X/*                                 */
  1142. X/* Permission is granted to use    */
  1143. X/* this program and to freely copy */
  1144. X/* it and/or source code as long   */
  1145. X/* as these notices remain.        */
  1146. X/* No charges for these copies may */
  1147. X/* be made, except for handling    */
  1148. X/* and distribution fees.          */
  1149. X
  1150. X/* This program puts customized menus into the WorkBench menubar.      */
  1151. X/* The program is split up into two parts, MyMenu and MyMenu-Handler.  */
  1152. X/* This section is MyMenu and it initializes and starts up a process   */
  1153. X/* to run MyMenu-Handler, and then terminates.  MyMenu also terminates */
  1154. X/* and cleans up after the suprocess.  MyMenu will parse the users     */
  1155. X/* menus, initialize data to be passed to MyMenu-Handler, and start    */
  1156. X/* up MyMenu-Handler.  MyMenu-Handler does very little memory          */
  1157. X/* allocation in order to save space, so MyMenu does allocation and    */
  1158. X/* freeing for it.                                                     */
  1159. X
  1160. X#include <exec/types.h>
  1161. X#include <exec/memory.h>
  1162. X#include <graphics/gfxbase.h>
  1163. X#include <intuition/intuitionbase.h>
  1164. X#include <libraries/dos.h>
  1165. X#include <libraries/dosextens.h>
  1166. X#include <functions.h>
  1167. X#include <stdio.h>
  1168. X#include <ctype.h>
  1169. X#include "mymenu.h"
  1170. X
  1171. Xstatic char *copyright = "Copyright ) Darin Johnson, 1989";
  1172. X
  1173. X/* actually, I don't know if it will work under Lattice */
  1174. X#ifdef AZTEC_C
  1175. X#define strcmp _BUILTIN_strcmp
  1176. X#define strcpy _BUILTIN_strcpy
  1177. X#define strlen _BUILTIN_strlen
  1178. X#endif
  1179. X
  1180. Xstruct IntuitionBase *IntuitionBase = NULL;
  1181. Xstruct GfxBase *GfxBase = NULL;
  1182. X
  1183. Xextern int menu_num;
  1184. X
  1185. X/* this is the data structure that we use to pass data to MyMenu-Handler */
  1186. Xstruct MMData *MM;
  1187. X
  1188. Xchar do_quit;
  1189. Xint i;
  1190. X
  1191. X/* make (and allocate) a copy of the passed string */
  1192. Xchar *copystr(str)
  1193. Xchar *str;
  1194. X{
  1195. X  char *newstr;
  1196. X  newstr = AllocMem(strlen(str)+1, MEMF_PUBLIC);
  1197. X  strcpy(newstr, str);
  1198. X  return newstr;
  1199. X}
  1200. X
  1201. X/* strcmp, ignoring case */
  1202. X#define UPPER(c) (islower(c)?toupper(c):(c))
  1203. Xint stricmp(s, t)
  1204. X  char *s, *t;
  1205. X{
  1206. X  for ( ; UPPER(*s) == UPPER(*t); s++, t++)
  1207. X    if (*s== NULL)
  1208. X      return 0;
  1209. X  return UPPER(*s) - UPPER(*t);
  1210. X}
  1211. X
  1212. X/* Find the workbench window - I'm sure there's a better way... */
  1213. Xstruct Window *find_workbench() {
  1214. X  struct Screen *scr;
  1215. X  struct Window *win;
  1216. X  ULONG ilock;
  1217. X  ilock = LockIBase(0L);    /* just so's things don't change on us */
  1218. X  for (scr = IntuitionBase->FirstScreen;    /* find WB Screen */
  1219. X       scr && strcmp(scr->DefaultTitle, "Workbench Screen");
  1220. X       scr=scr->NextScreen);
  1221. X  if (!scr) {
  1222. X    UnlockIBase(ilock);
  1223. X    printf("That's odd...  I can't find the workbench screen...\n");
  1224. X    _abort(2000);
  1225. X  }
  1226. X  for (win=scr->FirstWindow; win; win = win->NextWindow)
  1227. X    if (win->Flags & WBENCHWINDOW) break;      
  1228. X  UnlockIBase(ilock);
  1229. X  return win;
  1230. X}
  1231. X
  1232. X/* open a library */
  1233. XAPTR *open_lib(name, rev)
  1234. Xchar *name;
  1235. Xlong rev;
  1236. X{
  1237. X  APTR *lib;
  1238. X  if ((lib = (APTR*)OpenLibrary(name, rev)) == NULL) {
  1239. X    printf("Can't open %s (rev=%d\n", name, rev);
  1240. X    _abort(1000);
  1241. X  }
  1242. X  return lib;
  1243. X}
  1244. X
  1245. X/* make a copy of our CLI path.  We also convert BCPL stuff. */
  1246. Xcopy_path() {
  1247. X  register struct Path *oldpath, *newpath, *tmppath;
  1248. X  struct CommandLineInterface *cli;
  1249. X  struct Process *pr;
  1250. X  
  1251. X  pr = (struct Process *)FindTask(NULL);
  1252. X  cli = (struct CommandLineInterface *)BADDR(pr->pr_CLI);
  1253. X  newpath = MM->CLI_path = NULL;
  1254. X  for (oldpath = (struct Path *)BADDR(cli->cli_CommandDir); oldpath;
  1255. X              oldpath = (struct Path *) BADDR(oldpath->path_Next)) {
  1256. X    tmppath = (struct Path *)AllocMem(sizeof(struct Path), MEMF_PUBLIC);
  1257. X    if (!MM->CLI_path) {
  1258. X      MM->CLI_path = tmppath;
  1259. X    } else {
  1260. X      newpath->path_Next = tmppath;    /* we don't convert to BCPL */
  1261. X    }
  1262. X    newpath = tmppath;
  1263. X    tmppath->path_Next = NULL;
  1264. X    tmppath->path_Lock = DupLock(oldpath->path_Lock);
  1265. X  }
  1266. X}
  1267. X
  1268. X/* free up the space used by the copy of the CLI path */
  1269. Xfree_path() {
  1270. X  register struct Path *tmp, *path;
  1271. X      /* clean out copy of path */
  1272. X  path = MM->CLI_path;
  1273. X  MM->CLI_path = NULL;
  1274. X  while (path) {
  1275. X    tmp = path;
  1276. X    path = path->path_Next;
  1277. X    UnLock(tmp->path_Lock);
  1278. X    FreeMem(tmp, sizeof(struct Path));
  1279. X  }
  1280. X}
  1281. X
  1282. X/* Initialize and load up the handler process, or update the menus */
  1283. X/* for an existing handler.                                        */
  1284. Xadd_handler() {
  1285. X  ULONG ilock;
  1286. X
  1287. X  if (MM) {
  1288. X      /* remove old menus and update */
  1289. X    printf("Updating menus -- ");
  1290. X    fflush(stdout);
  1291. X      /* coordinate with handler */
  1292. X    MM->parent_task = FindTask(NULL);
  1293. X    MM->parent_sig = AllocSignal(-1L);
  1294. X    Signal(MM->handler_task, SIGBREAKF_CTRL_D);
  1295. X    Wait(1 << MM->parent_sig);
  1296. X      /* clean old stuff up */
  1297. X    free_menus();
  1298. X    ilock = LockIBase(0L);
  1299. X    menu_num = 0;
  1300. X    for (MM->prev_menu = MM->WBWindow->MenuStrip;
  1301. X    MM->prev_menu->NextMenu;
  1302. X    MM->prev_menu=MM->prev_menu->NextMenu)
  1303. X      menu_num++;
  1304. X    UnlockIBase(ilock);
  1305. X
  1306. X      /* get new menus */
  1307. X    if (!parse_menus()) {
  1308. X      do_quit = TRUE;
  1309. X      return;
  1310. X    }
  1311. X
  1312. X      /* let handler know it can continue */
  1313. X    Signal(MM->handler_task, SIGBREAKF_CTRL_D);
  1314. X    printf("ok\n");
  1315. X    return;
  1316. X  }
  1317. X
  1318. X    /* create a new handler */  
  1319. X  printf("Installing MyMenu -- ");
  1320. X  fflush(stdout);
  1321. X
  1322. X    /* get area to pass data in */
  1323. X  MM = (struct MMData *)AllocMem(sizeof(struct MMData), MEMF_PUBLIC|MEMF_CLEAR);
  1324. X
  1325. X  MM->WBWindow = find_workbench();
  1326. X  if (MM->WBWindow==NULL) {
  1327. X    printf("Can't find Workbench...\n");
  1328. X    do_quit = TRUE;
  1329. X    return;
  1330. X  }
  1331. X
  1332. X    /* we need to find out what menu number ours start at */
  1333. X  ilock = LockIBase(0L);
  1334. X  menu_num = 0;
  1335. X  for (MM->prev_menu = MM->WBWindow->MenuStrip;
  1336. X    MM->prev_menu->NextMenu;
  1337. X    MM->prev_menu=MM->prev_menu->NextMenu)
  1338. X    menu_num++;
  1339. X  UnlockIBase(ilock);  
  1340. X
  1341. X    /* read in user's menus */
  1342. X  if (!parse_menus()) {
  1343. X    do_quit = TRUE;
  1344. X    return;
  1345. X  }
  1346. X
  1347. X  MM->port.mp_Flags = PA_IGNORE;    /* we'll get msg's from do_wbrun */
  1348. X  MM->port.mp_Node.ln_Pri = 0;
  1349. X  MM->port.mp_Node.ln_Type = NT_MSGPORT;
  1350. X  MM->port.mp_Node.ln_Name = copystr(MYMENU_NAME);
  1351. X  NewList(&MM->port.mp_MsgList);
  1352. X
  1353. X    /* load in handler */
  1354. X  MM->segment = LoadSeg("l:MyMenu-Handler");
  1355. X  if (!MM->segment)
  1356. X    MM->segment = LoadSeg("MyMenu-Handler");
  1357. X  if (!MM->segment) {
  1358. X    printf("Can't find L:MyMenu-Handler\n");
  1359. X    do_quit = TRUE;
  1360. X    return;
  1361. X  }
  1362. X
  1363. X    /* add to port list so that handler can find it */
  1364. X  AddPort(&MM->port);
  1365. X
  1366. X  MM->parent_task = FindTask(NULL);
  1367. X  MM->parent_sig = AllocSignal(-1L);
  1368. X  copy_path();
  1369. X  CreateProc(MYMENU_NAME, 0, MM->segment, STACK);
  1370. X    /* handshake so that we know it got started ok */
  1371. X  Wait(1 << MM->parent_sig);
  1372. X  FreeSignal(MM->parent_sig);
  1373. X  if (MM->error_code) {
  1374. X    printf("Handler error (%d)\n", MM->error_code);
  1375. X    do_quit = TRUE;
  1376. X  } else {
  1377. X    printf("ok - %s\n", VERSION);
  1378. X  }
  1379. X}
  1380. X
  1381. X/* shutdown and clean up after handler */
  1382. Xremove_handler() {
  1383. X  if (!MM)
  1384. X    return;
  1385. X  printf("removing -- ");
  1386. X  fflush(stdout);
  1387. X  if (MM->segment != NULL) {
  1388. X    MM->parent_task = FindTask(NULL);
  1389. X    MM->parent_sig = AllocSignal(-1L);
  1390. X    Signal(MM->handler_task, SIGBREAKF_CTRL_C);
  1391. X
  1392. X      /* wait until handler cleans up */
  1393. X      /* (don't advertise that we catch ^C - for emergency use only) */
  1394. X    Wait(1 << MM->parent_sig);
  1395. X    FreeSignal(MM->parent_sig);
  1396. X    if (MM->error_code != ERR_OK) {
  1397. X      /* we can get an error if there are outstanding WB processes */
  1398. X      printf("Leaving handler in place...\n");
  1399. X      return;
  1400. X    }
  1401. X    RemPort(&MM->port);
  1402. X    UnLoadSeg(MM->segment);
  1403. X  }
  1404. X    /* this is done here, not in handler... */
  1405. X  free_path();
  1406. X  free_menus();
  1407. X  if (MM->port.mp_Node.ln_Name)
  1408. X    FreeMem(MM->port.mp_Node.ln_Name, strlen(MM->port.mp_Node.ln_Name)+1);
  1409. X  FreeMem(MM, sizeof(struct MMData));
  1410. X  printf("done\n");
  1411. X}
  1412. X
  1413. X/* Close up libraries and exit.  Having a routine named _abort() is */
  1414. X/* handy for use with SDB, otherwise, I would have a better name.   */
  1415. X_abort(st)
  1416. X  int st;
  1417. X{
  1418. X  if (IntuitionBase)
  1419. X    CloseLibrary(IntuitionBase);
  1420. X  if (GfxBase)
  1421. X    CloseLibrary(GfxBase);
  1422. X  exit(st);
  1423. X}
  1424. X
  1425. Xmain(argc, argv)
  1426. X  int argc;
  1427. X  char *argv[];
  1428. X{
  1429. X  IntuitionBase = (struct IntuitionBase *)open_lib("intuition.library", 0L);
  1430. X  GfxBase = (struct GfxBase *)open_lib("graphics.library", 0L);
  1431. X  
  1432. X  do_quit=FALSE;
  1433. X  for (i=1; i<argc; i++) {
  1434. X    if (stricmp(argv[i], "QUIT")==0) {
  1435. X      do_quit=TRUE;
  1436. X      continue;
  1437. X    }
  1438. X      /* no other options yet */
  1439. X    printf("Usage: MyMenu [quit]\n");
  1440. X    _abort(10);
  1441. X  }
  1442. X
  1443. X    /* find shared data (if it exists) */
  1444. X  MM = (struct MMData *)FindPort(MYMENU_NAME);
  1445. X
  1446. X  if (do_quit == FALSE) {
  1447. X    add_handler();
  1448. X  };
  1449. X  if (do_quit==TRUE) {        /* note that this isn't an 'else' */
  1450. X      remove_handler();
  1451. X  }
  1452. X  _abort(0);
  1453. X}
  1454. SHAR_EOF
  1455. echo "extracting MyMenu.conf"
  1456. sed 's/^X//' << \SHAR_EOF > MyMenu.conf
  1457. X# this is a sample configuration file.
  1458. Xcolor 2
  1459. Xmenu DMouse "DMouse On" | CLI fd0:utilities/dmouse -R0008 -l0008 -A2 -Q0008 "<nil: >nil: newcon:320/120/320/80/NewCLI"
  1460. Xmenu DMouse "Dmouse Off" | CLI fd0:utilities/dmouse quit
  1461. Xmenu <T> Stuff "Games   ;" Tetrix | WB fd0:games/tetrix
  1462. Xmenu <B> Stuff "Games   ;" "Black Box" | WB fd0:games/Black Box
  1463. Xmenu <S> Stuff "Games   ;" "Sorry!" | WB fd0:games/Sorry!
  1464. Xmenu <C> Stuff "Games   ;" Kamikaze | CLI fd0:games/KamikazeChess
  1465. Xmenu <N> Stuff NewCLI | CLI c:newcli newcon:320/100/0/0/NewCLI
  1466. Xmenu <V> Stuff VT100 | CLI fd0:comm/vt100
  1467. Xcolor 3
  1468. Xmenu Stuff "MyMenu Quit" | CLI fd0:progs/mymenu/mymenu quit
  1469. SHAR_EOF
  1470. echo "extracting MyMenu.doc"
  1471. sed 's/^X//' << \SHAR_EOF > MyMenu.doc
  1472. XMyMenu is a program to allow you to create your own menus in the WorkBench
  1473. Xto run your own commands.  This can save the hassle of opening up lots
  1474. Xof drawers to get to the command you want.  MyMenu will allow you to execute
  1475. Xboth CLI and WorkBench programs, and is configured with a normal text
  1476. Xfile.  Hopefully, this program will be obsolete when WorkBench 1.4
  1477. Xis released, since I hear this capability may be added.
  1478. X
  1479. XBuilding:
  1480. X
  1481. X  There is a supplied Makefile, which works with Manx 3.6, and a version
  1482. X  of make from a Fish disk (I don't remember which one).  The Makefile
  1483. X  should work with most make programs.  I haven't tried to get this
  1484. X  to work with 16-bit integers, or to work with Lattice (although, I
  1485. X  would like this).
  1486. X
  1487. X  There are some defines in MyMenu.h that can be customized.  DO_WB
  1488. X  determines if support for WorkBench programs is included.  Undefining
  1489. X  this can save a lot of space if you don't need this option.  DO_PATH
  1490. X  if defined will compile in code for path searching for commands.
  1491. X  Currently, it is undefined.
  1492. X
  1493. XInstallation:
  1494. X
  1495. X  Copy MyMenu-Handler to the L: directory.  MyMenu will also look
  1496. X  for this file in the current directory if it does not exist in
  1497. X  the L: directory.
  1498. X
  1499. X  Create the file S:MyMenu.conf.  The format of this file is described
  1500. X  later.
  1501. X
  1502. XRunning:
  1503. X
  1504. X  Step one is to start up the Workbench!
  1505. X  
  1506. X  The command "MyMenu" will load and start up the handler process.
  1507. X  Menus should now appear in the WorkBench menu strip.
  1508. X  
  1509. X  Running MyMenu while the handler is already loaded will cause
  1510. X  it to re-parse the configuration file and rebuild the menus.
  1511. X
  1512. X  The command "MyMenu quit" will terminate and unload the handler
  1513. X  process.
  1514. X
  1515. XConfiguration file:
  1516. X
  1517. X  The configuration file is read in when you run MyMenu.  It is
  1518. X  looked for in the S: directory, and in the current directory in
  1519. X  that order.
  1520. X
  1521. X  The configuration file defines the menus you want, and what commands
  1522. X  they will run.  You may put carriage returns between keywords, but
  1523. X  you cannot put a carriage return in the middle of a command.
  1524. X  Comments begin with a #, and continue until the end of the line.
  1525. X  Upper and lowercase does not make a difference.
  1526. X
  1527. X  COLOR n
  1528. X
  1529. X    This will set the foreground pen color for new menus.  You can
  1530. X    change this as often as you want.  The arguments is number that is
  1531. X    the pen number to use.  The default is 2 (black).
  1532. X
  1533. X  MENU [<command-char>] menu-name item-name [sub-item-name] | command-def
  1534. X
  1535. X    Defines a new menu.  Each menu definition must have a menu-name and
  1536. X    an item-name.  A sub-item-name is optional.  If any of these names
  1537. X    contain whitespace, enclose the name in double quotes, or precede
  1538. X    the whitespace character with a backslash (\).  A command character
  1539. X    may be defined for the menu item by putting the character after the
  1540. X    MENU keyword and surround it with <>'s.
  1541. X
  1542. X    Separate the menu definition and the command definition with a vertical
  1543. X    bar (|).  After the bar, you can have the keywords CLI or WB, to
  1544. X    specify that the command is a CLI or WorkBench command.  Everything
  1545. X    after WB until the end of the line is taken to be the command.
  1546. X    Everything after CLI until a space or end of the line is taken to be
  1547. X    the command.  Everything else will be passed as arguments to the
  1548. X    CLI command.  Do not include redirection in a CLI command.
  1549. X
  1550. X  Examples:
  1551. X
  1552. X    menu Games Tetrix | WB dh0:games/tetrix
  1553. X
  1554. X      This will define a menu "Games", with a menu item "Tetrix".
  1555. X      If this is selected, the command "dh0:games/tetrix" will be run
  1556. X      as a WorkBench program.
  1557. X
  1558. X    menu Games "Black Box" | WB df0:Black Box
  1559. X
  1560. X      This will define a menu item "Black Box" under the menu "Games".
  1561. X      The menu Games will already exist from the previous example, and
  1562. X      will now contain "Tetrix" and "Black Box" as items.  The command
  1563. X      to be run is "df0:Black Box" (Box is not an argument).
  1564. X
  1565. X    color 3
  1566. X    menu  Utilities DMouse "Start DMouse" | c:DMouse
  1567. X    menu  Utilities DMouse "Quit DMouse" | c:DMouse quit
  1568. X
  1569. X      This will define two sub menu items (drawn in yellow).  The second
  1570. X      command has an argument.
  1571. X
  1572. XFuture plans and hopeless dreams:
  1573. X  AREXX support.
  1574. X  Fix up path searching.
  1575. X  A better parser.
  1576. X  Support for graphical menu items.
  1577. X
  1578. XLimitations, bugs, and other wierd things:
  1579. X  Path searching does not work.  Do not compile this in.
  1580. X  I would appreciate it if someone can find the problem, since I
  1581. X  am stuck.  Details are in DoRun.c.
  1582. X
  1583. X  New preferences causes menus to disappear (but handler is not unloaded).
  1584. X  The menus can be rebuilt by running MyMenu again.
  1585. X
  1586. X  Redirection can not be done for CLI programs, since the code already
  1587. X  does redirection to and from NIL:.
  1588. X
  1589. X  Line limit of 256 characters in configuration file.
  1590. X
  1591. XAcknowledgements:
  1592. X
  1593. X  I have borrowed ideas and code snipits from other public domain
  1594. X  programs.  I have also received help directly from some people.
  1595. X  I would like to thank those people (whose names I remember):
  1596. X  
  1597. X    Matt Dillon        - Ideas for menu building and how to load in the
  1598. X                          handler were taken from DME and DMouse.
  1599. X    Peter da Silva    - Ideas taken from wblaunch program.
  1600. X    Rob Peck        - Some ideas and help.
  1601. X    Davide Cervone    - LOTS of ideas taken from MonIDCMP.
  1602. X
  1603. XSignature:
  1604. X
  1605. X  Darin Johnson
  1606. X  darin@laic.UUCP
  1607. X  {leadsv!laic!darin@pyramid.pyramid.com}
  1608. X  (415) 368-0972
  1609. SHAR_EOF
  1610. echo "extracting MyMenu.h"
  1611. sed 's/^X//' << \SHAR_EOF > MyMenu.h
  1612. X/* Copyright ) Darin Johnson, 1989 */
  1613. X
  1614. X#define VERSION "MyMenu v1.0"
  1615. X
  1616. X#define MYMENU_NAME "MyMenu"
  1617. X#define WBPORT_NAME "MyMenu-WBPort"
  1618. X
  1619. X#define DO_WB
  1620. X/* #define DO_PATH    - not working yet */
  1621. X/* #define DO_AREXX     - future plans... */
  1622. X
  1623. X#define SEPARATE 32    /* distance between menus */
  1624. X#define STACK 4096    /* 2048 is too small */
  1625. X
  1626. Xstruct ext_MenuItem {
  1627. X  struct MenuItem MenuItem;
  1628. X  struct ext_MenuItem *next_item;
  1629. X  ULONG id;
  1630. X  char *cmd;
  1631. X  char *args;
  1632. X  char type;
  1633. X};
  1634. X
  1635. Xstruct Path {
  1636. X  struct Path *path_Next;
  1637. X  struct FileLock *path_Lock;
  1638. X};
  1639. X
  1640. X/* would declare whole thing 'volatile' if allowed */
  1641. Xstruct MMData {
  1642. X  struct MsgPort port;
  1643. X  struct ext_MenuItem *item_list;
  1644. X  struct Menu *my_menu, *prev_menu, *WBMenu;
  1645. X  struct Window *WBWindow;
  1646. X  struct Task *handler_task, *parent_task;
  1647. X  USHORT parent_sig, handler_sig;
  1648. X  char error_code;
  1649. X  struct Segment *segment;
  1650. X  struct Path *CLI_path;        /* copy of CLI path */
  1651. X};
  1652. X
  1653. Xextern struct MMData *MM;
  1654. Xextern struct ext_MenuItem *add_menu();
  1655. X
  1656. X/* error codes */
  1657. X#define ERR_OK        0
  1658. X#define ERR_LIB        1
  1659. X#define ERR_WIN        2
  1660. X#define ERR_MON        3
  1661. X#define ERR_WB_OPEN    4
  1662. SHAR_EOF
  1663. echo "extracting Parse.c"
  1664. sed 's/^X//' << \SHAR_EOF > Parse.c
  1665. X/* Copyright ) Darin Johnson, 1989 */
  1666. X
  1667. X#include <exec/types.h>
  1668. X#include <intuition/intuition.h>
  1669. X#include <stdio.h>
  1670. X#include <ctype.h>
  1671. X#include "mymenu.h"
  1672. X
  1673. X#define STR 1
  1674. X
  1675. X#define SYNTAX(msg) { fprintf(stderr, "Error parsing MyMenu.conf: %s\n"); \
  1676. X            return FALSE; }
  1677. X
  1678. X#ifdef AZTEC_C
  1679. X#define strcmp _BUILTIN_strcmp
  1680. X#define strcpy _BUILTIN_strcpy
  1681. X#define strlen _BUILTIN_strlen
  1682. X#endif
  1683. X
  1684. XFILE *conf;
  1685. Xchar tok[256], menustr[256], itemstr[256], substr[256];
  1686. X
  1687. Xextern UBYTE menu_pen;
  1688. X
  1689. Xmake_action(mi, typ, action)
  1690. X  struct ext_MenuItem *mi;
  1691. X  char typ, *action;
  1692. X{
  1693. X  register char *p, *index(), *rindex(), *copystr();
  1694. X
  1695. X  mi->args = mi->cmd = NULL;
  1696. X  if (typ=='c') {    /* CLI */
  1697. X    if (*action == '"') {
  1698. X      action++;
  1699. X      p = index(action, '"');
  1700. X    } else {
  1701. X      p = index(action, ' ');
  1702. X    }
  1703. X    if (p) {    /* if arguments */
  1704. X      *p++ = NULL;
  1705. X      mi->args = copystr(p);
  1706. X    }
  1707. X    mi->cmd = copystr(action);
  1708. X    mi->type = 'C';
  1709. X  } else if (typ=='w') {
  1710. X    if (*action=='"') {
  1711. X      action++;
  1712. X      p = rindex(action, '"');
  1713. X      *p = NULL;
  1714. X    }
  1715. X    mi->cmd = copystr(action);
  1716. X    mi->type = 'W';
  1717. X  }
  1718. X}
  1719. X
  1720. Xchar get_token()
  1721. X{
  1722. X  char quote;
  1723. X  register char c, *p;
  1724. Xretry:
  1725. X  c = fgetc(conf);
  1726. X  while(isspace(c)) c=fgetc(conf);    /* skip extra spaces */
  1727. X  if (c=='#') {                /* comment */
  1728. X    while((c=fgetc(conf))!='\n' && c!=EOF);
  1729. X    goto retry;
  1730. X  }
  1731. X  if (!isalnum(c) && c!='"')
  1732. X    return c;
  1733. X    /* scan string */
  1734. X  if (c=='"') {
  1735. X    c = fgetc(conf);
  1736. X    quote = TRUE;
  1737. X  } else
  1738. X    quote = FALSE;
  1739. X  p = tok;
  1740. X  do {
  1741. X    if ((quote && c=='"') || (!quote && isspace(c)))
  1742. X      break;
  1743. X    if (c=='\\')
  1744. X      c = fgetc(conf);
  1745. X    if (isspace(c))
  1746. X      c = ' ';
  1747. X    *p++ = c;
  1748. X  } while ((c=fgetc(conf))!=EOF);
  1749. X  *p = NULL;
  1750. X  return STR;
  1751. X}
  1752. X
  1753. Xint parse_conf() {
  1754. X  register char t;
  1755. X  char *p, c, flag, cmd;
  1756. X  struct ext_MenuItem *mi;
  1757. X    
  1758. X  while ((t=get_token()) != EOF) {
  1759. X    if (t==STR) {
  1760. X      if (stricmp(tok, "MENU")==0) {
  1761. X        cmd = NULL;
  1762. X        if ((t=get_token())=='<') {    /* command char */
  1763. X      cmd = fgetc(conf);
  1764. X      if (get_token() != '>')
  1765. X        SYNTAX("Missing closing'>'");
  1766. X      t=get_token();
  1767. X    }
  1768. X        if (t==STR)
  1769. X      strcpy(menustr, tok);
  1770. X    else
  1771. X      SYNTAX("Missing menu name");
  1772. X        if (get_token()==STR)
  1773. X      strcpy(itemstr, tok);
  1774. X    else
  1775. X          SYNTAX("Missing menu item name");
  1776. X    if ((t=get_token())==STR) {
  1777. X      strcpy(substr, tok);
  1778. X          t=get_token();
  1779. X    } else {
  1780. X      substr[0] = NULL;
  1781. X    }
  1782. X    if (t != '|')
  1783. X      SYNTAX("Missing '|' separator");
  1784. X    mi = add_menu(menustr, itemstr, substr, cmd);
  1785. X    if (get_token() != STR)
  1786. X      SYNTAX("Syntax error after '|'");
  1787. X        /* find out type */
  1788. X    if (stricmp(tok, "CLI")==0)
  1789. X      flag = 'c';
  1790. X    else if (stricmp(tok, "WB")==0)
  1791. X      flag = 'w';
  1792. X    else
  1793. X      flag = NULL;
  1794. X        /* read in command (rest of line */
  1795. X    p = tok;
  1796. X    while ((c=fgetc(conf)) != '\n' && c!=EOF)
  1797. X      *p++ = c;
  1798. X    *p = NULL;
  1799. X    make_action(mi, flag, tok);
  1800. X      } else if (stricmp(tok, "COLOR")==0) {
  1801. X        if ((t=get_token())!=STR)
  1802. X          SYNTAX("Expected number after COLOR keyword");
  1803. X        menu_pen = (UBYTE)atoi(tok);
  1804. X      } else
  1805. X        SYNTAX("Didn't find keyword");
  1806. X    } else
  1807. X      SYNTAX("Didn't find keyword");
  1808. X  }
  1809. X  return TRUE;
  1810. X}
  1811. X
  1812. Xint parse_menus() {
  1813. X  int stat;
  1814. X  conf = fopen("S:MyMenu.conf", "r");
  1815. X  if (conf==NULL) {
  1816. X    conf = fopen("MyMenu.conf", "r");
  1817. X    if (conf==NULL) {
  1818. X      fprintf(stderr, "Can't open MyMenu.conf!\n");
  1819. X      return FALSE;
  1820. X    }
  1821. X  }
  1822. X  start_menu();
  1823. X  menu_pen = 2;
  1824. X  stat = parse_conf();
  1825. X  end_menu();
  1826. X  if (conf)
  1827. X    fclose(conf);
  1828. X  return stat;
  1829. X}
  1830. SHAR_EOF
  1831. echo "extracting README"
  1832. sed 's/^X//' << \SHAR_EOF > README
  1833. XMyMenu is a program to allow you to create your own menus in the WorkBench
  1834. Xto run your own commands.  This can save the hassle of opening up lots
  1835. Xof drawers to get to the command you want.  MyMenu will allow you to execute
  1836. Xboth CLI and WorkBench programs, and is configured with a normal text
  1837. Xfile.  Hopefully, this program will be obsolete when WorkBench 1.4
  1838. Xis released, since I hear this capability may be added.
  1839. X
  1840. XSee the MyMenu.DOC file for complete information.
  1841. X
  1842. XThis is the first release, so there are bound to be a few bugs.  Let me
  1843. Xknow about them.
  1844. X
  1845. X
  1846. XDarin Johnson
  1847. Xdarin@laic.UUCP
  1848. X{leadsv!laic!darin@pyramid.pyramid.com}
  1849. SHAR_EOF
  1850. echo "extracting newbugs"
  1851. sed 's/^X//' << \SHAR_EOF > newbugs
  1852. X- These are relatively minor, but annoying ...
  1853. X
  1854. X  In order to run a WorkBench program, there has to be a .info file
  1855. X  for the tool and/or project.  This means that XIcon and IconX
  1856. X  can't be used as is.  However, Execute can be used in their place.
  1857. X  
  1858. X  If you create a NewCLI or use Execute, you will get an empty
  1859. X  path, and the current directory will be the initial boot device.
  1860. X  The same sort of problems occur with DMouse and other programs.
  1861. SHAR_EOF
  1862. echo "End of archive 1 (of 1)"
  1863. # if you want to concatenate archives, remove anything after this line
  1864. exit
  1865.